Digital Inputs and Outputs via I/O Adapters Basic

Motivation

Sometimes it is desirable to either set digital output pins or react to changes on digital input pins. In this tutorial we will create an actor that periodically toggles a digital output and another one that will react to changes on a digital input. Output and input will be wired together, so that we have a loopback system.

Pre-requisites

  • You have a working miniHIL project setup which you either created using the template project or the example project.

  • You have basic eTrice knowldge. E.g. you successfully finished the eTrice PingPong Tutorials.

  • For the loopback to work you will need to connect Digital input 0 with digital output 16 using a wire jumper as shown in the picture below:

DigitalIOWiring
  • To be able to see some output, make sure you can log as described in here. Note that in this case you only need the USB connection. Log messages will be generated by both actors.

Tip The contents of this How-To is also part of the miniHIL Examples project. Look there for a fully functional sample in model-user/examples/digitalio.room.

Accessing digital I/Os using adapters

Note Digital I/Os can be accessed using two different mechanisms. One way is to directly use the digital input and output service provision points (SPP). This is however not recommended for beginners.
The other option, which is described in this HowTo, is to use the provided I/O-adapters.

Digital output adapters

The PDigOut protocol is used to set digital outputs. If the digital output adapters are used, only the following protocol messages are used:

/* setting output to high */
Message setOutputHigh()

/* setting output to low */
Message setOutputLow()

/* setting output to tristate*/
Message setOutputTristate()

To use a digital output adapter simply add a new actor reference to your room model. As type for the new actor reference you have to choose one of the digital out adapters provided by the model lib. The naming scheme for digital out adapters is ADigOutAdapterXXtoYY. Digital output adapters always contain 4 ports. XX and YY are the first and last digital output ports contained in the adapter. The output port names directly map to the pin labels on the miniHIL board. Digital outputs are pins 16 to 31.

Digital input adapters

The PDigIn protocol is used to react to changes on digital inputs. If the digital input adapters are used, only the following protocol messages are used:

/* notification for change to input high */
Message inputHigh()

/* notification for change to input low */
Message inputLow()

To use a digital input adapter simply add a new actor reference to your room model. As type for the new actor reference you have to choose one of the digital in adapters provided by the model lib. The naming scheme for digital in adapters is ADigInAdapterXXtoYY. Digital input adapters always contain 4 ports. XX and YY are the first and last digital input port contained in the adapter. The input port names directly map to the pin labels on the miniHIL board. Digital inputs are pins 0 to 15.

Note A digital input only generates a inputHigh or inputLow message if the input pin changes. The digital inputs are default high.

Creating The Actors

For this tutorial we will create an output and an input actor. Both will be placed inside MiniHilProject/model-user/MiniHILApplication.room.

A couple of imports are needed for them to work:

import etrice.api.timer.PTimer
import etrice.api.logger.PLogger
import minihil.api.digital.PDigIn
import minihil.api.digital.PDigOut
import minihil.api.adapters.io.*

The Output Actor

First of all, we create the output actor and its structure. Add the following lines to MiniHilApplication.room:

ActorClass ADigitalOutWriter {
	Structure {
		ActorRef outputAdapter: ADigOutAdapter16to19 1
		conjugated Port outPort: PDigOut 2
		Binding outPort and outputAdapter.digOut16 3
		SAP timer: PTimer 4
		SAP logger: PLogger 5
		Attribute outputState: boolean 6
	}
	Behavior {
	}
}
1 We use the adapter that allows us to access the digital outputs 16 to 19
2 This port is needed to connect the adapter to the state machine we will create in the next step
3 Connecting the actor-internal port to the adapter
4 The timer service is used to receiver periodic timer ticks
5 The logging service is used to print out the state of the output
6 This attribute stores the value that we will set on the digital output

As of now the actor will not do anything. We need to add behavior by adding a state maching. Place the cursor on ADigitalOutWriter and press ALT-B to open the behavior editor.

As of now it is empty, so add an initial state.

Also add a state called OutputIsHigh. This state will set the output to high when entered. To do so configure the state as shown in the picture below:

DigitalIOOutputIsHigh

Similarly we will need a state OutputIsLow that switches the output to low. It needs to be configured as follows:

DigitalIOOutputIsLow

Please note in both cases that the outPort is used to set the adapter and therefore the output to the desired state.

Now we need to add transitions for the FSM to work. First of all, we need a transition from init to OutputIsHigh. In this we will start the timer that will trigger the periodic state changes between high and low.
Configure the transition as follows:

DigitalIOInitTransition

From OutputIsHigh we need a transition to OutputIsLow. This will be triggered by a timeout message from the timer service. Setup the transition as follows:

DigitalIOSwitchToLow

Similarly we want to go back to OutputIsHigh. So a corresponding transition needs to be added:

DigitalIOSwitchToHigh

The overall state machine should now look like this:

DigitalIOOutputFSM

Your actor should now look as follows (states and transitions may appear in a different order):

ActorClass ADigitalOutWriter {
	Structure {
	    ...
	}
	Behavior {
		StateMachine {
			State OutputIsHigh {
				entry '''
					logger.log("Setting output to high");
					outPort.setOutputHigh();
				'''
			}
			State OutputIsLow {
				entry '''
					logger.log("Setting output to low");
					outPort.setOutputLow();
				'''
			}
			Transition init: initial -> OutputIsHigh {
				action '''
					timer.startTimer(1000);
				'''
			}
			Transition switchToLow: OutputIsHigh -> OutputIsLow {
				triggers {
					<timeout: timer>
				}
			}
			Transition switchToHigh: OutputIsLow -> OutputIsHigh {
				triggers {
					<timeout: timer>
				}
			}
		}
	}
}

The Input Actor

The input actor will simply react to messages coming from the input adapter representing the current state. Lets start with the structure first. Add the following code:

ActorClass ADigitalInReader {
	Structure {
		ActorRef inputAdapter: ADigInAdapter00to03 1
		conjugated Port inPort: PDigIn 2
		Binding inPort and inputAdapter.digIn00 3
		SAP logger: PLogger 4
	}
	Behavior {
	}
}
1 We use the adapter that allows us to access the digital inputs 0 to 3
2 This port is needed to connect the adapter to the state machine we will create in the next step
3 Connecting the actor-internal port to the adapter
4 The logging service is used to print out the state of the input

As before we need to add a state machine for the actor to do anything. Open the behavior editor and add an initial state and the state called Waiting. In Waiting we will simply wait for state changes from the input. Here no entry actions are necessary. But we need a transition from init to Waiting for the state machine to get started. This does not require any action code.

The adapter reports state changes from the input using inputHigh and inputLow messages. Therefore Waiting needs two self-transitions, one for each message. In them we will log the message that caused the transition.

For inputHigh the transition is as follows:

DigitalIOReceivedHigh

For inputLow it is accordingly:

DigitalIOReceivedLow

The overall state machine should look like this now:

DigitalIOInputFSM

The final actor should now look like this:

ActorClass ADigitalInReader {
	Structure {
	    ...
	}
	Behavior {
		StateMachine {
			State Waiting
			Transition init0: initial -> Waiting
			Transition receivedHigh: Waiting -> Waiting {
				triggers {
					<inputHigh: inPort>
				}
				action '''
					logger.log("Input is now high");
				'''
			}
			Transition receivedLow: Waiting -> Waiting {
				triggers {
					<inputLow: inPort>
				}
				action '''
					logger.log("Input is now low");
				'''
			}
		}
	}
}

Instantiating The Actors

As a final step we need to instantiate the actors. Put the following code inside the Application actor:

RoomModel MiniHilProject {
    ...
	ActorClass Application {
		Structure {
			ActorRef writer: ADigitalOutWriter
			ActorRef reader: ADigitalInReader
		}
	}
}

Running The Example

Now you can finally build and run the example. When you connect your terminal you should see the following output, uptading every second:

DigitalIOOutput

Summary

  • Digital I/O Adapters can be used to set and react to digital I/Os.

  • Digital I/O Adapters are specified in the minihil.adapters.api.io namespace.

  • Digital in adapters are named ADigInAdapterXXtoYY (pins 0-15).

  • Digital out adapters are named ADigOutAdapterXXtoYY (pins 16-31).

See Also